package server

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/hmac"
	cryptoRand "crypto/rand"
	"encoding/binary"
	"encoding/gob"
	"fmt"

	"github.com/google/uuid"

	//"github.com/zrynuaa/cpabe06_client/bswabe"
	"hash"
	"io"
	"log"
	mathRand "math/rand"
	"net/http"
	"os"
	"reflect"
)

//var pub *bswabe.BswabePub
//var prv *bswabe.BswabePrv

// 获取ABE服务器上的主公钥
//func GetABEKeys(attrs string) (*bswabe.BswabePub, *bswabe.BswabePrv) {
//
//	client, err := rpc.DialHTTP("tcp", "10.141.211.220:1234")
//	if err != nil {
//		log.Fatal("dialing:", err)
//	}
//
//	// Synchronous call同步方式调用
//	var reply []byte
//	err = client.Call("CPABE.Getpub", "", &reply)
//	if err != nil {
//		log.Fatal(" error:", err)
//	}
//	pub = bswabe.UnSerializeBswabePub(reply) //获取PublicKey
//
//	err = client.Call("CPABE.Getsk", attrs, &reply)
//	if err != nil {
//		log.Fatal("arith error:", err)
//	}
//	prv = bswabe.UnSerializeBswabePrv(pub, reply) //获取服务端返回的解密私钥
//
//	return pub, prv
//}

func AddHandletoServer(server *http.ServeMux, filename string) {
	fss := http.FileServer(http.Dir(os.Getenv("GOPATH") + "/src/github.com/zrynuaa/medicine_blockchain/frontend/static"))
	fsh := http.FileServer(http.Dir(os.Getenv("GOPATH") + "/src/github.com/zrynuaa/medicine_blockchain/frontend/html"))
	server.Handle("/static/", http.StripPrefix("/static/", fss))
	server.Handle("/html/"+filename, http.StripPrefix("/html/", fsh))
}

// 处理policy，加密数据
func processContCR(cr ContCR) ContCR {

	//prepolicy := "IRSID RINID 1of2 R 2of2"
	//policy1 := strings.Replace(prepolicy, "IRSID", cr.Company, -1)
	//policy := strings.Replace(policy1, "RINID", cr.ReCompany, -1)
	//加密

	//01上传CR信息 获取前端传递的参数
	//02 生成KDF派生需要的密钥
	//Mkey for KDF
	keyLength := 16
	MKey, err := generateRandomKey(keyLength)
	if err != nil {
		fmt.Println("Error generating random key:", err)
	}

	//03 将CR和密钥一起属性加密
	// ConPolicy := "A B C 1of3"
	//RWPolicy := "R 1of1 W R 1of2"
	//FullPolicy := "A B C 1of3 R 1of1 W R 1of2 2of2" //test data

	///////
	//var attrs = cr.ReCompany
	var pub, _ = GetABEKeys(attrs) //获取ABE服务上的密钥对

	// transform to bytes
	var result bytes.Buffer
	temp := cr
	encoder := gob.NewEncoder(&result)
	err1 := encoder.Encode(temp)
	if err1 != nil {
		log.Panic(err1)
	}
	result.Write(MKey)

	//EnCompany := bswabe.SerializeBswabeCphKey(bswabe.CP_Enc(pub, cr.Company, policy))
	//EnReCompany := bswabe.SerializeBswabeCphKey(bswabe.CP_Enc(pub, cr.ReCompany, policy))
	//Enriskcode := bswabe.SerializeBswabeCphKey(bswabe.CP_Enc(pub, cr.riskcode, policy))
	//Enperiod := bswabe.SerializeBswabeCphKey(bswabe.CP_Enc(pub, cr.period, policy))

	EnCompany := "001"
	EnReCompany := "002"
	Enriskcode := "003"
	Enperiod := "365"

	var EnCRdata ContCR
	EnCRdata.ContNo = cr.ContNo
	EnCRdata.ContName = cr.ContName
	EnCRdata.Company = string(EnCompany)
	EnCRdata.ReCompany = string(EnReCompany)
	EnCRdata.period = string(Enperiod)
	EnCRdata.hashadd = cr.hashadd
	EnCRdata.riskcode = string(Enriskcode)
	EnCRdata := bswabe1.SerializeBswabeCphKey(bswabe1.CP_Enc(pub, Desc, FullPolicy))

	return EnCRdata
}

func generateRandomKey(length int) ([]byte, error) {
	key := make([]byte, length)

	_, err := mathRand.Read(key)
	if err != nil {
		return nil, err
	}

	return key, nil
}

// HKDF
func hkdfExtract(salt, inputKeyMaterial []byte, hashFunc func() hash.Hash) []byte {
	hashLen := hashFunc().Size()

	if salt == nil || len(salt) == 0 {
		salt = make([]byte, hashLen)
	}

	h := hmac.New(hashFunc, salt)
	h.Write(inputKeyMaterial)
	prk := h.Sum(nil)

	return prk
}

func hkdfExpand(pseudoRandomKey, info []byte, length int, hashFunc func() hash.Hash) []byte {
	hashLen := hashFunc().Size()
	length = length

	// 计算需要的块数
	blocksNeeded := (length + hashLen - 1) / hashLen
	okm := make([]byte, 0)
	outputBlock := make([]byte, 0)

	for counter := 0; counter < blocksNeeded; counter++ {
		// 计算每个块的输出
		h := hmac.New(hashFunc, pseudoRandomKey)
		h.Write(outputBlock)
		h.Write(info)
		counterBytes := make([]byte, 4)
		binary.BigEndian.PutUint32(counterBytes, uint32(counter+1))
		h.Write(counterBytes)
		outputBlock = h.Sum(nil)

		// 将输出块追加到最终输出
		okm = append(okm, outputBlock...)
	}

	return okm[:length]
}

type Hkdf struct {
	prk []byte
}

func NewHkdf(salt, inputKeyMaterial []byte, hashFunc func() hash.Hash) *Hkdf {
	prk := hkdfExtract(salt, inputKeyMaterial, hashFunc)

	return &Hkdf{prk: prk}
}

func (h *Hkdf) Expand(info []byte, length int, hashFunc func() hash.Hash) []byte {
	return hkdfExpand(h.prk, info, length, hashFunc)
}

// AES加密
func encrypt(plaintext []byte, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	// 创建GCM（Galois/Counter Mode）模式
	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	// 生成随机的nonce（一次性使用的值）
	nonce := make([]byte, gcm.NonceSize())
	if _, err := io.ReadFull(cryptoRand.Reader, nonce); err != nil {
		return nil, err
	}

	ciphertext := gcm.Seal(nil, nonce, plaintext, nil)
	result := append(nonce, ciphertext...)

	return result, nil
}

// AES解密
func decrypt(ciphertext []byte, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	nonceSize := gcm.NonceSize()
	if len(ciphertext) < nonceSize {
		return nil, fmt.Errorf("ciphertext is too short")
	}
	nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]

	plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
	if err != nil {
		return nil, err
	}

	return plaintext, nil
}

func generateUUID() string {
	newUUID, err := uuid.NewRandom()
	if err != nil {
		fmt.Println("Error generating UUID:", err)
		return ""
	}
	return newUUID.String()
}

func convertMap(obj interface{}) map[string]string {
	result := make(map[string]string)

	val := reflect.ValueOf(obj)
	if val.Kind() != reflect.Struct {
		fmt.Println("Input is not a struct")
	}

	typ := val.Type()

	for i := 0; i < val.NumField(); i++ {
		field := val.Field(i)
		fieldName := typ.Field(i).Name

		// 将字段值转换为字符串
		strValue := fmt.Sprint(field.Interface())

		// 将键值对添加到 map 中
		result[fieldName] = strValue
	}

	return result
}
